package scaladuct;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import util.SerializationUtils;

import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays;

/**
 * <p/>
 * Created by IntelliJ IDEA.
 * User: zslajchrt
 * Date: Feb 14, 2011
 * Time: 1:01:42 PM
 */
public class AnnotSerialProbe {

    public static void main(String[] args) throws Exception {
        Class<?> klass = new ClassLoader(Thread.currentThread().getContextClassLoader()) {

            @Override
            protected URL findResource(String name) {
                return super.findResource(name);    //To change body of overridden methods use File | Settings | File Templates.
            }

            @Override
            protected Class<?> findClass(String name) throws ClassNotFoundException {
                return super.findClass(name);
            }

            public Class<?> defineClass() {
                ClassWriter cw = new ClassWriter(0);
                cw.visit(Opcodes.V1_6, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER,
                        "Foo", null, "java/lang/Object", new String[]{"java/io/Serializable"});
                for (int i = 0; i < 3; i++) {
                    FieldVisitor fv = cw.visitField(0, "value" + i, "I", null, null);
                    fv.visitAnnotation("LBar;", true).visitEnd();
                }

// creates a MethodWriter for the (implicit) constructor
                MethodVisitor mw = cw.visitMethod(Opcodes.ACC_PUBLIC,
                        "<init>",
                        "()V",
                        null,
                        null);
                // pushes the 'this' variable
                mw.visitVarInsn(Opcodes.ALOAD, 0);
                // invokes the super class constructor
                mw.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
                mw.visitInsn(Opcodes.RETURN);
                // this code uses a maximum of one stack element and one local variable
                mw.visitMaxs(1, 1);
                mw.visitEnd();

                cw.visitEnd();
                byte[] bytes = cw.toByteArray();
                return defineClass("Foo", bytes, 0, bytes.length);
            }
        }.defineClass();

        Thread.currentThread().setContextClassLoader(klass.getClassLoader());
        Object obj = klass.newInstance();
        Object obj2 = SerializationUtils.deserialize(SerializationUtils.serialize(obj));

        for (Field f : klass.getDeclaredFields()) {
            System.out.println(f + " " + Arrays.toString(f.getAnnotations()));
        }
    }

}
